{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modParsingClassIElements;

interface

uses modParsingClassBase,
     modBaseType,
     Classes,
     sFonctionsChaines,
     SysUtils,
     Windows,

     modClassElements,

     LibXmlParser;


type
    TParsingElementsGID = class(IParsingRedirection)
    private
       //
       // Informations qui vont être extraites
       //

       // Liste des éléments
       FElementsList : TListElements;

       // Adresse du formulaire si c'est une page du genre
       // 'flotte' ou 'défense'
       FFormAction: string;


       
       // Définit si on ne peut pas construire d'élément parce qu'il y a
       // déjà un élément en cours de construction
       // Définit à partir de la balise script
       // Car de toute façon, tout les élément auront link à ''
       FCannotBuild: boolean;










       //
       // Variables qui vont aider à se repérer dans la page
       //

       FInForm : boolean;
       FInTable: boolean;
       FInLink : boolean;
       FInLinkInfoElementStr: boolean;
       FNextContentIsMaybeNiveau: boolean;
       FNextMaybeScriptDurationConstruction : boolean;

       FInScript: boolean;



       FCurrTableLigne: integer;
       FCurrTableColonne: integer;


       FNbElementTrouve: integer;

       

       //
       // Variables qui vont aider à l'extraction des données
       //

       FCurrElement: POGItemCost;

       // Permet d'extraire les données seulement à la fin du <br>
       // sans tenir compte des balises <b>
       FInRessourceNeed: boolean;

       FRessourceNeedStr: string;


       //
       // Variables paramètres
       //

       // Determine si on est en mode "form" ou non, c'est à dire si c'est
       // un formulaire que l'on doit remplir ou juste un lien où l'on doit cliquer
       // Ceci différencie les recherches/batiments de chantier spatial/defenses
       FFormMode: boolean;




       procedure InitPointeur;


    public
       // type de GID actuellement parsé
       // définit à l'extérieur, vu que ce même parseur est utilisé pour les 4 types de GID
       GidType: TTypeGID;


       property ElementsList : TListElements read FElementsList;
       property FormAction   : string        read FFormAction;

       property CannotBuild  : boolean       read FCannotBuild;



       /////////////////////////////////////////////////////////////////////////
       // Implémentation de IParsingRedirection

        // initialise l'interface
        procedure Initialisation; override;

        // obtient le résultat d'analyse
        function  GetFinalState: TParsingResultState; override;

        procedure SetFullURLFromBase(const BaseLink: string); override;


        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
        procedure ScanOnEndTag(Sender: TObject; TagName: string); override;
        procedure ScanOnContent(Sender: TObject; Content: string); override;

       //
       /////////////////////////////////////////////////////////////////////////


       constructor Create;
       destructor Destroy; override;
    end;
     
implementation

uses modLanguageParsing, modCore, sHTMLFonctions;


constructor TParsingElementsGID.Create;
begin
    inherited;

    FElementsList := TListElements.Create;
end;

destructor TParsingElementsGID.Destroy;
begin
    FElementsList.ClearAndDispose;
    FElementsList.Free;
    
    inherited;
end;

procedure TParsingElementsGID.Initialisation;
begin

       // Liste des éléments
       FElementsList.ClearAndDispose;

       // Adresse du formulaire si c'est une page du genre
       // 'flotte' ou 'défense'
       FFormAction := '';


       
       // Définit si on ne peut pas construire d'élément parce qu'il y a
       // déjà un élément en cours de construction
       // Définit à partir de la balise script
       // Car de toute façon, tout les élément auront link à ''
       FCannotBuild := false;




       //
       // Variables qui vont aider à se repérer dans la page
       //

       FInForm := false;
       FInTable:= false;
       FInLink := false;
       FInLinkInfoElementStr:= false;
       FNextContentIsMaybeNiveau:= false;
       FNextMaybeScriptDurationConstruction := false;

       FInScript:= false;



       FCurrTableLigne   := 0;
       FCurrTableColonne := 0;


       FNbElementTrouve  := 0;



       //
       // Variables qui vont aider à l'extraction des données
       //

       FCurrElement := nil;

       // Permet d'extraire les données seulement à la fin du <br>
       // sans tenir compte des balises <b>
       FInRessourceNeed  := false;

       FRessourceNeedStr := '';

end;

function TParsingElementsGID.GetFinalState: TParsingResultState;
begin
    Result := PRESULT_ECHEC;

    {$IFDEF DEBUG_PARSING}
         FElementsList.DebugProc := FDebugProcParsing;
         FElementsList.SendToDebugAllInfo;
    {$ENDIF}

    if FError then begin
       exit;
    end;

    Result := NoT(PRESULT_ECHEC);
end;

procedure TParsingElementsGID.SetFullURLFromBase(const BaseLink: string);
begin
    inherited;
    
    if FFormAction <> '' then begin
       FFormAction := sHTML_Get_URL_Lien(BaseLink, FFormAction);
    end;
    
end;


procedure TParsingElementsGID.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    xPos : integer;
begin
   TagName := lowercase(TagName);


   if TagName = 'form' then begin

      // Dans la nouvelle version, il y a deux formulaires, dont un inutile
      // celui inutile correspond à un GET, tandis que l'autre est un POST
      CurrBalise := Attributes.Value('method');

      if SameText(CurrBalise, 'post') then begin
         FInForm := true;
         FFormAction := Attributes.Value('action');
      end;



   end else if TagName = 'table' then begin
      FInTable := true;

      FCurrTableLigne  := 0;
      FCurrTableColonne := 0;


   end;

   if FFormMode and (FInForm = false) then exit;
   if NoT(FInTable) then exit;

   if TagName = 'tr' then begin
      // Nouvelle ligne
      FCurrTableColonne := 0;
      Inc(FCurrTableLigne);

      if FCurrElement <> nil then begin
         // On le sauvegarde
         if FCurrElement.Gid > 0 then begin
            FCurrElement.GIDType       := GetTypeOfTGID(FCurrElement.GID);
            FElementsList.Add(FCurrElement);

         end else
            // Pointeur invalide
            Dispose(FCurrElement);

         FCurrElement := nil;
      end;

   end else if (TagName = 'td') or (TagName = 'th') then begin
      Inc(FCurrTableColonne);

   end else if TagName = 'a' then begin
      FInLink := true;

      if FCurrTableColonne = 2 then begin
          // Lien pour avoir des informations sur l'élément
          // Ce lien est utile car il permet d'extraire le GID de l'élément
          // <a href=infos.php?session=00000000&gid=202>
          // Et il va aussi permettre d'extraire le nom de l'élément


          CurrBalise := Attributes.Value('href');
          CurrBalise := lowercase(CurrBalise);

          xPos := pos('&gid=', CurrBalise);
          if xPos > 0 then begin
              FInLinkInfoElementStr := true;

              System.Delete(CurrBalise, 1, xPos + 4);

              // Au cas où d'autre paramètre sont après le gid
              xPos := pos('&', CurrBalise);
              if xPos > 0 then
                 System.Delete(CurrBalise, xPos, maxint);


              try
                 xPos := StrToIntDef(CurrBalise, -1);
              except
                 xPos := -2;
              end;

              if xPos < 0 then begin
                  // Echec de conversion
                  FError := true;

              end else begin
                  // Sinon c'est ici que l'élément se créer et prend forme
                  if FCurrElement <> nil then begin
                     // on le sauvegarde
                     //FRes.Add(FCurrElement);
                     //FCurrElement := nil;
                     // Il a du déjà être sauvegardé lors du changement de ligne
                     FError := true;
                  end;

                  // Créé un nouvel élément
                  New(FCurrElement);
                  InitPointeur;

                  FCurrElement.Gid := xPos;

              end;


          end;


      end else if FCurrTableColonne = 3 then begin
          // Lien de construction
          // <a href=b_building.php?session=00000000&bau=21&cp=1111111>

          // si c'est avec le compte commandant
          // on a un lien pour annuler la construction
          // mais FCurrElement est à nil

          if FCurrElement = nil then begin

             if FElementsList.Count > 0 then begin
                // pour le premier élément, il se peut donc
                // que ce soit le compte commandant
                FError := true;
             end;

          end else
             FCurrElement.Link := Attributes.Value('href');


      end;

   end else if TagName = 'input' then begin

      if FCurrTableColonne = 3 then begin
          // Zone de saisie pour indiquer le nombre d'unité à construire
          // <input type=text name=fmenge[205] alt='Chasseur lourd' size=6 maxlength=6 value=0 tabindex=1>

          if FCurrElement = nil then
             FError := true
          else
             FCurrElement.Link := Attributes.Value('name');


      end;

   end else if TagName = 'br' then begin
      if FInRessourceNeed then begin
         // Traite le tampon FInLinkInfoElementStr
         // Métal:<b>3.000</b> Cristal:<b>1.000</b> Deutérium:<b>0</b> Énergie:<b>0</b><br>
         // Donc:
         // Métal:3.000 Cristal:1.000 Deutérium:0 Énergie:0

         FInRessourceNeed := false;

         if FCurrElement <> nil then begin
            FCurrElement.Prix := mpcExtractRessourceFromBuffer(FRessourceNeedStr);
         end;

      end;

   end else if TagName = 'script' then begin
      // pp="5380";pk="3";pl="13401692";ps="0000000";t();
      // A première vu, pp correspond au nombre de seconde restante avant
      // la fin de la construction

      // <a href=b_building.php?session="+ps+"&cp="+pl+">

      if FCurrTableColonne = 3 then begin
         // Cellule de construction
         if FCurrElement <> nil then begin

            FCurrElement.EnConstruction := true;
            FCannotBuild := true;

            FInScript := true;

            FNextMaybeScriptDurationConstruction := true;

            // FCurrElement.ConstructionFinDans
         end;

      end;


   end;

end;

procedure TParsingElementsGID.ScanOnEndTag(Sender: TObject; TagName: string);
begin
   TagName := lowercase(TagName);

   if TagName = 'form' then begin
      FInForm := false;

   end else if TagName = 'table' then begin
      FInTable := false;

      if FCurrElement <> nil then begin
         FCurrElement.GIDType       := GetTypeOfTGID(FCurrElement.GID);
         FElementsList.Add(FCurrElement);
         FCurrElement := nil;
      end;

      FCurrTableLigne  := 0;
      FCurrTableColonne := 0;


   end else if TagName = 'script' then begin
      FInScript := false;

   end else if TagName = 'a' then begin
      FInLink := false;
      FInLinkInfoElementStr := false;

   end;

end;


procedure TParsingElementsGID.ScanOnContent(Sender: TObject; Content: string);
label lblDispoChantier;
var xPos, i, lng, xPos2: integer;
    s, xPosStr: string;
begin

// Message lorsque l'on est en train de mettre à jour le centre de recherche:
// "Tu ne peux pas faire de recherche car le centre de recherche est en construction."
// Et les liens de recherche sont pourtant disponible, donc ce qu'il faut faire,
// c'est d'une part vérifie si la recherche a bien commencé après le lancement
// de l'une d'entre elles.



    if FCurrTableColonne = 3 then begin

        if FInScript then begin

          if FNextMaybeScriptDurationConstruction then begin
              // pp="159";pk="1";pl="33601757";ps="0000000011";t();
              xPos := pos('pp', Content);

              if xPos = 0 then exit;
              System.Delete(Content, 1, xPos + 2);  // +2 pour enlever le =

              xPos := pos('"', Content);
              if xPos = 0 then exit;

              System.Delete(Content, 1, xPos);

              xPos := pos('"', Content);
              if xPos = 0 then exit;
              System.Delete(Content, xPos, maxint);

              try
                  if FCurrElement <> nil then
                     FCurrElement.ConstructionFinDans := StrToIntDef(Content, -1)
                  else
                     FError := true;

              except
                  FCurrElement.ConstructionFinDans := -1;
              end;

              FNextMaybeScriptDurationConstruction := false;

          end;

       end;

    end;



    // Le contenu utile n'est que celui de la colone 2
    if FCurrTableColonne <> 2 then exit;
    if NoT(FInTable) then exit;


    if FInLinkInfoElementStr then begin
        // <a href=infos.php?session=1111111111&gid=202>Petit transporteur</a>
        if FCurrElement = nil then
           FError := true
        else
           FCurrElement.Nom := Content;

        FInLinkInfoElementStr := false;
        FNextContentIsMaybeNiveau := true;

    end else if FNextContentIsMaybeNiveau then begin
        FNextContentIsMaybeNiveau := false;

        //  (Niveau 11 )
        Content := lowercase(Content);




        xPosStr := LangParsing.GetData('building_poslw_niveau', 'niveau');
        xpos := pos(xPosStr, Content);

        xPos2 := pos(LangParsing.GetData('chantierdef_poslw_disponible', 'disponible'), Content);


        if xPos > 0 then begin

           if (xPos2 > 0) then begin
               // pour le portugal, la chaine pour "niveau" est
               // incluse dans la chaine "disponible"
               if xPos2 < xPos then begin
                  goto lblDispoChantier;
               end;
           end;


           System.Delete(Content, 1, xPos + length(xPosStr));
           Content := trimleft(Content);

           lng := length(Content);
           if lng < 1 then exit;

           s := '';
           for i := 1 to lng do begin
              if Content[i] in sfc_ChiffresSet then begin
                 s := s + Content[i];
              end else
                 break;

           end;

           if s <> '' then begin
              xPos := StrToIntDef(s, -1);

              if xPos > 0 then begin
                 if FCurrElement = nil then
                    FError := true
                 else
                    FCurrElement.Niveau := xPos;

                 exit;
              end;

           end;

        end else begin
           //   ( 4 disponible(s) )
lblDispoChantier:
           xPos := pos(LangParsing.GetData('chantierdef_poslw_disponible', 'disponible'), Content);

           if xPos > 0 then begin
              Content := copy(Content, 1, xPos - 1);
              Content := trimright(Content);

              xPos := LastDelimiter(' ()', Content);
              if xPos > 0 then begin
                  System.Delete(Content, 1, xPos);

                  Content := sfcRemplace(Content, '.', '');
                  xPos := StrToIntDef(Content, -1);

                  if xPos < 0 then exit;

                  if FCurrElement = nil then
                     FError := true
                  else
                     FCurrElement.Niveau := xPos;
              end;

           end;


        end;




    end else if FInRessourceNeed then begin
        if Content <> '' then begin
          // Le parseur supprime tout seul les espaces superflus
          // On rajoute l'espace intelligement
          
          if NoT(Content[1] in sfc_ChiffresSet) then
             Content := ' ' + Content;

          FRessourceNeedStr := FRessourceNeedStr + Content;
        end;

    end else begin

        // Les majuscules sont inutile ici
        Content := lowercase(Content);


        // chantierdef_lw_duree_construct
        xPos := pos(LangParsing.GetData('items_lw_duree_construct', ' de construction :'), Content);
        if xPos > 0 then begin
           // <br>Durée de production:  19m 12s<br>
           // Durée de production: 8h 18m 47s
           // Durée de production: 1 Jour 1h 36m 00s
           // Durée de construction :  21m 20s<br>

           xPos := pos(':', Content);
           if xPos > 0 then begin
              System.Delete(Content, 1, xPos);
              Content := trimleft(content);

              if FCurrElement = nil then
                 FError := true
              else begin
                 FCurrElement.Duree := mpcExtractDureeFromStr(Content);
                 if FCurrElement.Duree < 0 then
                    FError := true;

              end;
           end;

           exit;
        end;



        xPos := pos(LangParsing.GetData('building_poslw_ressources_necessaire', 'essources nécessaires :'), lowercase(Content));
        if xPos > 0 then begin
           // <br>A besoin de: Métal:<b>3.000</b> Cristal:<b>1.000</b> Deutérium:<b>0</b> Énergie:<b>0</b><br>
           // Ressources nécessaires : Métal:
           xPos := pos(':', Content);
           System.Delete(Content, 1, xPos);
           FRessourceNeedStr := trimleft(content);
           FInRessourceNeed  := true;
        end;


    end;



end;



procedure TParsingElementsGID.InitPointeur;
begin
    FCurrElement.GID             := -1;
    FCurrElement.Prix.Metal      :=  0;
    FCurrElement.Prix.Cristal    :=  0;
    FCurrElement.Prix.Deuterium  :=  0;
    FCurrElement.Prix.Energie    :=  0;

    
    FCurrElement.Duree           :=  0;
    FCurrElement.CanBeBuildIn    := -1;
    FCurrElement.CanBeBuildInOpt := -1;

    FCurrElement.Link            := '';
    FCurrElement.Nom             := '';
    FCurrElement.Niveau          := 0;
    FCurrElement.EnConstruction  := false;

    
    FCurrElement.LigneInGrid  := -1;
    FCurrElement.GIDType       := tgidAutre;
    FCurrElement.ConstructionFinDans := -1;
end;

end.
